/**
 * @file photo.c
 * @brief 提供扫描目录、管理图片文件列表的功能
 * @details 该文件实现了双向链表的基本操作（插入节点），
 * 并通过扫描指定目录，将找到的 .jpg 和 .bmp 文件路径存入链表中。
 * @version 1.0
 * @date 2025-07-05
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dirent.h>     // 包含目录操作函数 opendir, readdir, closedir
#include "jpeglib.h"
#include "photo.h"      // 假设定义了 Node 结构体
#include "lcd.h"
#include "ts.h"

/**
 * @brief 向双向链表的末尾插入一个新节点
 * @param head      链表的头指针
 * @param filename  要存储在新节点中的文件名（路径）
 * @return Node* 返回链表的头指针。如果原链表为空，则返回新节点的地址。
 */
Node *insert(Node *head, const char *filename) {
    // 1. 为新节点分配内存空间
    Node *newnode = (Node *)malloc(sizeof(Node));
    if (newnode == NULL) {
        perror("malloc for new node failed");
        return head; // 内存分配失败，返回原头指针
    }

    // 2. 初始化新节点的数据和指针
    strcpy(newnode->filename, filename); // 将文件名拷贝到新节点
    newnode->next = NULL; // 新节点是末尾节点，所以 next 指向 NULL
    newnode->prev = NULL; // prev 暂时指向 NULL

    // 3. 处理空链表的情况
    if (head == NULL) {
        // 如果链表是空的，新节点就是头节点
        return newnode;
    }

    // 4. 找到链表的最后一个节点
    Node *p = head;
    while (p->next != NULL) {
        p = p->next; // 循环直到 p 指向最后一个节点
    }

    // 5. 将新节点链接到链表末尾
    p->next = newnode;   // 原尾节点的 next 指向新节点
    newnode->prev = p;   // 新节点的 prev 指向原尾节点

    // 6. 返回原链表的头指针
    return head;
}

/**
 * @brief 打印双向链表中所有节点存储的文件名 (主要用于调试)
 * @param head 链表的头指针
 */
void print_list(Node *head) {
    Node *p = head;
    printf("--- File List ---\n");
    // 遍历链表，从头到尾
    while (p != NULL) {
        printf("%s\n", p->filename); // 打印当前节点的文件名
        p = p->next; // 移动到下一个节点
    }
    printf("-----------------\n");
}

/**
 * @brief 扫描指定目录，并将找到的图片文件路径添加到链表中
 * @details 该函数会遍历目录，查找后缀为 .jpg 或 .bmp 的文件，
 * 然后将它们的完整路径添加到传入的链表中。
 * @param dir   要扫描的目录路径 (例如 "./res/images")
 * @param head  指向链表头指针的指针。因为函数需要修改调用者作用域中的头指针，
 * 所以必须使用二级指针。
 * @return int  成功返回0，打开目录失败或内存分配失败返回-1
 */
int scanf_list(const char *dir, Node **head) {
    // 1. 打开指定目录
    DIR *dp = opendir(dir);
    if (dp == NULL) {
        perror("opendir failed");
        return -1;
    }

    struct dirent *entry;
    // 2. 循环读取目录中的每一个条目
    while ((entry = readdir(dp)) != NULL)
    {
        // 3. 忽略 "." (当前目录) 和 ".." (上级目录)
        if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
        {
            continue; // 跳过本次循环，处理下一个条目
        }

        // 4. 检查文件名是否包含 ".jpg" 或 ".bmp" 后缀
        if (strstr(entry->d_name, ".jpg") != NULL || strstr(entry->d_name, ".bmp") != NULL)
        {
            // 5. 构建文件的完整路径 (目录 + 文件名)
            // 计算所需缓冲区的长度: 目录长度 + '/' + 文件名长度 + '\0'
            size_t len = strlen(dir) + strlen(entry->d_name) + 2;
            char *fullpath = (char *)malloc(len);
            if (fullpath == NULL)
            {
                perror("malloc for fullpath failed");
                closedir(dp); // 出错时也要记得关闭目录
                return -1;
            }
            // 使用 snprintf 安全地格式化字符串，防止缓冲区溢出
            snprintf(fullpath, len, "%s/%s", dir, entry->d_name);

            // 6. 将构建好的完整路径插入到链表中
            // *head 解引用，得到头指针本身，然后将其作为参数传递，并接收 insert 的返回值来更新它
            *head = insert(*head, fullpath);

            // 7. 释放临时路径字符串的内存
            // 因为 insert 函数内部使用 strcpy 复制了路径，所以这里的 fullpath 可以安全释放
            free(fullpath);
        }
    }

    // 8. 关闭目录，释放资源
    closedir(dp);
    return 0; // 扫描完成，成功返回
}